﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CandooMwrf
{
    public static class CardTye
    {
        /// <summary>
        /// 卡类型值，0x0004为M1卡，0x0010为ML卡
        /// </summary>
        /// <param name="TagType"></param>
        public static string GetCardTye(int TagType)
        {
            switch (TagType)
            {
                case 0x0004:
                    return "M1卡";
                    break;
                case 0x0010:
                    return "ML卡";
                    break;
                default:
                    break;
            }
            return "";
        }
    }

    /// <summary>
    /// 卡扇区
    /// </summary>
    public class CardSection
    {
        private static byte[] _EmptyBlock = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
        private static byte[] _EmptyKeyAB = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

        public CardSection()
        {
            block0 = new byte[16];
            block1 = new byte[16];
            block2 = new byte[16];
        }

        public static byte[] EmptyBlock
        {
            get
            {
                return _EmptyBlock;
            }
        }
        public static byte[] EmptyKeyAB
        {
            get
            {
                return _EmptyKeyAB;
            }
        }

        public byte[] block0 { get; set; }
        public byte[] block1 { get; set; }
        public byte[] block2 { get; set; }

        public byte[] KeyA { get; set; }
        public byte[] KeyControl { get; set; }
        public byte[] KeyB { get; set; }
    }

    public class CardDog
    {
        Random rnd = new Random();

        public ushort DogVersion
        {
            get { return 1; }
        }

        /// <summary>
        /// 通讯设备标识符
        /// </summary>
        public int Icdev { get; set; }
        public Int16 Port { get; set; }
        public int Baud { get; set; }

        public Action<string> ShowMessage;

        public int TryCount = 1;
        public CardDog()
        {

        }

        public string Connect(short port, int baud, bool IsCreatNew = false)
        {
            Port = port;
            Baud = baud;

            if (Icdev != 0 && IsCreatNew == false)
            {
                return "";
            }
            if (Icdev != 0)
            {
                try
                {
                    common.rf_exit(Icdev);
                }
                catch (Exception)
                {
                }
                Icdev = 0;
            }

            Icdev = common.rf_init(port, baud);
            var rtnMsg = "";
            if (Icdev > 0)
            {
                //common.rf_beep(Icdev, 5);
            }
            else
                rtnMsg = "读写卡器连接失败！\r\n返回代码" + Icdev + Result.GetErrorDesc(Icdev) + "\r\n操作提示:\r\n检查读卡器是否连接电脑\r\n检查读卡器是否打开\r\n检查读卡器端口与波特率是否选择正确";
            return rtnMsg;
        }
        public string Connect()
        {
            return Connect(Port, Baud);
        }

        public bool Disconnect()
        {
            var rtn = "";
            var st = common.rf_exit(Icdev);
            if (st != 0)
            {
                rtn = "断开连接失败！" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return false;
            }
            return true;
        }

        public int Beep()
        {
            var rtn = "";
            var st = common.rf_beep(Icdev, 10);
            if (st != 0)
            {
                rtn = "蜂呜失败！" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                //common.rf_exit(Icdev);
                //Icdev = 0;
            }
            return st;
        }

        /// <summary>
        /// 获取硬件版本
        /// </summary>
        /// <returns></returns>
        public string GetHardVer()
        {
            byte[] status = new byte[30];
            var st = common.rf_get_status(Icdev, status);
            if (st > 0)
                return System.Text.Encoding.GetEncoding("GB2312").GetString(status);
            else
                ShowMessage("获取硬件版本失败:" + Result.GetErrorDesc(st));
            return "";
        }
        public string GetSoftVer()
        {
            byte[] status = new byte[30];
            var st = common.lib_ver(status);
            if (st > 0)
                return System.Text.Encoding.GetEncoding("GB2312").GetString(status);
            else
                return "";
        }


        public Card NewCard(string cardNo)
        {
            Card card = new Card();

            //card.CrcCode;
            card.DogVersion = DogVersion;
            card.PublicKey = rnd.Next(int.MinValue, int.MaxValue);
            card.BirthDate = DateTime.Now;
            card.CardNo = cardNo;
            card.CardMoney = 0;
            card.CardType = 0;

            return card;
        }

        public int BurnCard(Card card)
        {

            var rtn = "";
            var st = -1;
            CardSection cardSection = new CardSection();

            //card.CrcCode;  //2
            byte[] dogVersion = BitConverter.GetBytes(card.DogVersion);//2
            byte[] PublicKey = BitConverter.GetBytes(card.PublicKey);//4
            byte[] BirthDate = BitConverter.GetBytes(card.BirthDate.Ticks);//8

            byte[] CardNo = System.Text.Encoding.ASCII.GetBytes(card.CardNo);//15字节,,首字节放长度
            //byte[] CardMoney = BitConverter.GetBytes(card.CardMoney);//4
            //byte[] CardType = BitConverter.GetBytes(card.CardType);//2

            byte[] block1 = new byte[16];
            byte[] block2 = new byte[16];

            Array.Copy(dogVersion, 0, block1, 2, 2);
            Array.Copy(PublicKey, 0, block1, 4, 4);
            Array.Copy(BirthDate, 0, block1, 8, 8);

            Array.Copy(CardNo,block2,CardNo.Length);
            //Array.Copy(CardMoney, 0, block2, 8, 4);
            //Array.Copy(CardType, 0, block2, 12, 2);

            card.CrcCode = ByteHexHelper.CRC16(block2);
            byte[] CrcCode = BitConverter.GetBytes(card.CrcCode);//2
            Array.Copy(CrcCode, 0, block1, 0, 2);

            byte[] desKey = ByteHexHelper.HexToByte(card.DesKey[0]);
            try
            {
                cardSection.block1 = ByteHexHelper.DESEncrypt(block1, desKey);
                cardSection.block2 = ByteHexHelper.DESEncrypt(block2, desKey);
            }
            catch (Exception)
            {
                ShowMessage("数据加密失败");
                return -2;
            }

            string skey = "FFFFFFFFFFFF";
            st = SeekCard(card, skey);
            if (string.IsNullOrEmpty(rtn) == false)
            {
                return st;
            }

            st = mifareone.rf_write(Icdev, 1, cardSection.block1);
            if (st != 0)
            {
                rtn += "写块1失败" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return st;
            }
            st = mifareone.rf_write(Icdev, 2, cardSection.block2);
            if (st != 0)
            {
                rtn += "写块2失败！" + Result.GetErrorDesc(st);
                return st;
            }

            st = mifareone.rf_changeb3(Icdev, 0, ByteHexHelper.HexToByte(card.KeyA[0]), 0x00, 0x00, 0x00, 0x01, 105, ByteHexHelper.HexToByte(card.KeyB[0]));
            if (st != 0)
            {
                rtn += "写块3失败！" + Result.GetErrorDesc(st);
                return st;
            }
            return st;
        }

        //取卡序列号
        public string GetCardSN()
        {
            string rtn = "";
            UInt16 tagtype = 0;
            byte size = 0;
            uint snr = 0;
            int sec = 0;

            mifareone.rf_reset(Icdev, 3);
            //0——表示IDLE模式，一次只对一张卡操作；
            //1——表示ALL模式，一次可对多张卡操作；
            //2——表示指定卡模式，只对序列号等于snr的卡操作（高级函数才有）

            var st = mifareone.rf_request(Icdev, 1, out tagtype);
            if (st != 0)
            {
                rtn = "寻卡请求出错!" + Result.GetErrorDesc(st);
                return rtn;
            }
            var cardType = CardTye.GetCardTye(tagtype);

            st = mifareone.rf_anticoll(Icdev, 0, out snr);
            if (st != 0)
            {
                rtn += "卡防冲突出错!" + Result.GetErrorDesc(st);
                return rtn;
            }
            string snrstr = "";
            snrstr = snr.ToString("X");
            ShowMessage("卡序列号:" + snrstr);
            return snrstr;
        }

        /// <summary>
        /// 寻卡
        /// </summary>
        /// <param name="icdev"></param>
        /// <param name="skey"></param>
        /// <returns></returns>
        private int SeekCard(Card card, string skey = "FFFFFFFFFFFF")
        {
            string rtn = "";
            UInt16 tagtype = 0;
            byte size = 0;
            uint snr = 0;
            int sec = 0;//扇区号

            mifareone.rf_reset(Icdev, 3);
            //0——表示IDLE模式，一次只对一张卡操作；
            //1——表示ALL模式，一次可对多张卡操作；
            //2——表示指定卡模式，只对序列号等于snr的卡操作（高级函数才有）
            var st = mifareone.rf_request(Icdev,1, out tagtype);
            if (st != 0)
            {
                rtn = "寻卡请求出错!" + Result.GetErrorDesc(st);
                return st;
            }
            var cardType = CardTye.GetCardTye(tagtype);

            st = mifareone.rf_anticoll(Icdev, 0, out snr);
            if (st != 0)
            {
                rtn += "卡防冲突出错!" + Result.GetErrorDesc(st);
                return st;
            }
            string snrstr = "";
            snrstr = snr.ToString("X");
            ShowMessage("卡防冲突时读出序列号:" + snrstr);
            ShowMessage("");
            if (card != null)
                card.CardSN = snrstr;
            st = mifareone.rf_select(Icdev, snr, out size);
            if (st != 0)
            {
                rtn += "选卡失败!" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return st;
            }

            byte[] key1 = new byte[17];
            byte[] key2 = new byte[7];
            int i = 0;

            if (skey.Length != 12)
            {
                rtn += "请正确输入密码，密码长度不对！";
                ShowMessage(rtn);
                return st;
            }

            for (i = 0; i < skey.Length; i++)
            {
                if (skey[i] >= '0' && skey[i] <= '9')
                    continue;
                if (skey[i] <= 'a' && skey[i] <= 'f')
                    continue;
                if (skey[i] <= 'A' && skey[i] <= 'F')
                    continue;
            }
            if (i != skey.Length)
            {
                rtn += "密码必须为十六进制数！";
                ShowMessage(rtn);
                return st;

            }
            key1 = Encoding.ASCII.GetBytes(skey);
            common.a_hex(key1, key2, 12);
            st = common.rf_load_key(Icdev, 0, sec, key2);
            if (st != 0)
            {
                rtn += "装载密码失败！" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return st;
            }
            st = mifareone.rf_authentication(Icdev, 0, sec);
            if (st != 0)
            {
                rtn = Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return st;
            }
            return st;
        }

        public bool IsBlankCard()
        {

            var st = SeekCard(null);
            if (st == 0)
            {
                ShowMessage("检测是否空卡成功:是空卡");
                ShowMessage("");
                return true;
            }
            ShowMessage("检测是否空卡结果:未知");
            ShowMessage("");
            return false;
        }

        public int ReadCard(out Card card)
        {
            card = new Card();
            var rtn = "";
            var st = -1;
            st = SeekCard(card, card.KeyA[0]);
            if (st != 0)
            {
                ShowMessage("寻卡失败");
                return st;
            }

            CardSection cardSection = new CardSection();

            int blocknr = 0;

            blocknr = 1;
            byte[] block1 = new byte[16];
            st = mifareone.rf_read(Icdev, blocknr, block1);
            if (st != 0)
            {
                rtn += "读块1失败" + Result.GetErrorDesc(st);
                ShowMessage("读块1:" + rtn);
                return st;
            }

            byte[] block2 = new byte[16];
            blocknr = 2;
            st = mifareone.rf_read(Icdev, blocknr, block2);
            if (st != 0)
            {
                rtn += "读块2失败" + Result.GetErrorDesc(st);
                ShowMessage("读块2:" + rtn);
                return st;
            }

            byte[] desKey = ByteHexHelper.HexToByte(card.DesKey[0]);
            try
            {
                cardSection.block1 = ByteHexHelper.DESDecrypt(block1, desKey);
                cardSection.block2 = ByteHexHelper.DESDecrypt(block2, desKey);
            }
            catch (Exception ex)
            {
                ShowMessage("数据解密失败" + ex.Message);
                return -3;
            }

            card.CrcCode = BitConverter.ToInt16(cardSection.block1, 0);
            card.DogVersion = BitConverter.ToUInt16(cardSection.block1, 2);
            card.PublicKey = BitConverter.ToUInt16(cardSection.block1, 4);
            var tmp = BitConverter.ToInt64(cardSection.block1, 8);
            card.BirthDate = new DateTime(tmp);

            var CRC16 = ByteHexHelper.CRC16(cardSection.block2);
            if(card.CrcCode != 0 && card.CrcCode != CRC16)
            {
                ShowMessage("卡数据校验失败");
                ShowMessage("");
                return -5;
            }

            card.CardNo = System.Text.Encoding.ASCII.GetString(cardSection.block2);
            //card.CardMoney = BitConverter.ToUInt32(cardSection.block2, 0);
            //card.CardType = BitConverter.ToUInt16(cardSection.block2, 8);

            return st;
        }

        /// <summary>
        /// 中止对该卡操作
        /// </summary>
        public void Halt()
        {
            mifareone.rf_halt(Icdev);//中止对该卡操作
        }

        public bool Clear()
        {
            var card = new Card();
            var rtn = "";
            var st = -1;
            st = SeekCard(card, card.KeyA[0]);
            //st = SeekCard(card, "000000000000");
            ShowMessage("寻卡失败");
            if (st != 0)
            {
                return false;
            }

            CardSection cardSection = new CardSection();

            var blocknr = 1;
            st = mifareone.rf_write(Icdev, blocknr, CardSection.EmptyBlock);
            if (st != 0)
            {
                rtn += "写块" + blocknr + "失败" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return false;
            }

            blocknr = 1;
            st = mifareone.rf_write(Icdev, blocknr, CardSection.EmptyBlock);
            if (st != 0)
            {
                rtn += "写块" + blocknr + "失败" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return false;
            }

            st = mifareone.rf_changeb3(Icdev, 0, CardSection.EmptyKeyAB, 0x00, 0x00, 0x00, 0x01, 105, CardSection.EmptyKeyAB);
            if (st != 0)
            {
                rtn += "写块3失败！" + Result.GetErrorDesc(st);
                ShowMessage(rtn);
                return false;
            }

            Halt();//中止对该止操作

            return true;
        }

    }
}
